#include "mainwindow.h"
#include "CityCode.h"
#include "qmenu.h"
#include "ui_mainwindow.h"

#define INCREMENT 3    //温度每升高/降低1°,y轴坐标的增量
#define POINT_RADIUS 3 //曲线描点的大小
#define TEXT_OFFSET_X 12
#define TEXT_OFFSET_Y 8

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //1.设置窗口属性
    setWindowFlag(Qt::FramelessWindowHint); //设置窗口无边框
    setFixedSize(width(), height());        //设置固定窗口大小

    //2.构建右键菜单
    mExitMenu = new QMenu(this);
    mExitACt = new QAction();
    mExitACt->setText("退出");
    mExitACt->setIcon(QIcon(":/close.png"));
    mExitMenu->addAction(mExitACt);
    connect(mExitACt, &QAction::triggered, this, [=]() {
        qApp->exit(0);
    }); //使用 QAction 的 triggered 信号来连接一个 lambda 函数,[=] { ... } 是一个 lambda 表达式

    //UI初始化
    //将控件添加到控件数组，方便使用循环进行处理
    //星期和日期
    mWeekList << ui->lb_Week1 << ui->lb_Week2 << ui->lb_Week3 << ui->lb_Week4 << ui->lb_Week5
              << ui->lb_Week6;
    mDateList << ui->lb_Date1 << ui->lb_Date2 << ui->lb_Date3 << ui->lb_Date4 << ui->lb_Date5
              << ui->lb_Date6;

    //天气和天气图标
    mTypeList << ui->lb_Weather1 << ui->lb_Weather2 << ui->lb_Weather3 << ui->lb_Weather4
              << ui->lb_Weather5 << ui->lb_Weather6;
    mTypeIconList << ui->lb_Type1 << ui->lb_Type2 << ui->lb_Type3 << ui->lb_Type4 << ui->lb_Type5
                  << ui->lb_Type6;

    //天气指数
    mAqiList << ui->lb_Quality1 << ui->lb_Quality2 << ui->lb_Quality3 << ui->lb_Quality4
             << ui->lb_Quality5 << ui->lb_Quality6;

    //风力和风向
    mFxList << ui->lb_Fx1 << ui->lb_Fx2 << ui->lb_Fx3 << ui->lb_Fx4 << ui->lb_Fx5 << ui->lb_Fx6;
    mFlList << ui->lb_FI1 << ui->lb_FI2 << ui->lb_FI3 << ui->lb_FI4 << ui->lb_FI5 << ui->lb_FI6;

    //天气图标
    mTypeMap.insert("暴雪", ":/type/BaoXue.png");
    mTypeMap.insert("暴雨", ":/type/BaoYu.png");
    mTypeMap.insert("暴雨到大暴雪", ":/type/BaoYuDaoDaBaoYu.png");
    mTypeMap.insert("大暴雨", ":/type/DaBaoYu.png");
    mTypeMap.insert("大暴雨到特大暴雪", ":/type/DaBaoYuDaoTeDaBaoYu.png");
    mTypeMap.insert("大到暴雪", ":/type/DaDaoBaoXue.png");
    mTypeMap.insert("大到暴雨", ":/type/DaDaoBaoYu.png");
    mTypeMap.insert("大雪", ":/type/DaXue.png");
    mTypeMap.insert("大雨", ":/type/DaYu.png");
    mTypeMap.insert("冻雨", ":/type/DongYu.png");
    mTypeMap.insert("多云", ":/type/DuoYun.png");
    mTypeMap.insert("浮沉", ":/type/FuChen.png");
    mTypeMap.insert("雷阵雨", ":/type/LeiZhenYu.png");
    mTypeMap.insert("雷阵雨伴有冰雹", ":/type/LeiZhenYuBanYouBingBao.png");
    mTypeMap.insert("霾", ":/type/Mai.png");
    mTypeMap.insert("强沙尘暴", ":/type/QiangShaChenBao.png");
    mTypeMap.insert("晴", ":/type/Qing.png");
    mTypeMap.insert("沙尘暴", ":/type/ShaChenBao.png");
    mTypeMap.insert("特大暴雨", ":/type/TeDaBaoYu.png");
    mTypeMap.insert("undefined", ":/type/undefined.png");
    mTypeMap.insert("雾", ":/type/Wu.png");
    mTypeMap.insert("小到中雨", ":/type/XiaoDaoZhongYu.png");
    mTypeMap.insert("小到中雪", ":/type/XiaoDaoZhongXue.png");
    mTypeMap.insert("小雪", ":/type/XiaoXue.png");
    mTypeMap.insert("小雨", ":/type/XiaoYu.png");
    mTypeMap.insert("雪", ":/type/Xue.png");
    mTypeMap.insert("扬沙", ":/type/YangSha.png");
    mTypeMap.insert("阴", ":/type/Yin.png");
    mTypeMap.insert("雨", ":/type/Yu.png");
    mTypeMap.insert("雨夹雪", ":/type/YuJiaXue.png");
    mTypeMap.insert("阵雪", ":/type/ZhenXue.png");
    mTypeMap.insert("中到大雪", ":/type/ZhongDaoDaXue.png");
    mTypeMap.insert("中到大雨", ":/type/ZhongDaoDaYu.png");
    mTypeMap.insert("中雪", ":/type/ZhongXue.png");
    mTypeMap.insert("中雨", ":/type/ZhongYu.png");

    //定位请求
    mLocationManger = new QNetworkAccessManager(this);
    connect(mLocationManger,
            &QNetworkAccessManager::finished,
            this,
            &MainWindow::onLocationInfoReceived);

    //3.网络天气请求
    mNetAccessManger = new QNetworkAccessManager(this);
    connect(mNetAccessManger, &QNetworkAccessManager::finished, this, &MainWindow::onReplied);

    locationInfo();
    //直接在构造中，请求天气Json数据
    //qDebug()<<mlocation.city;
    //getWeatherInfo("杭州");

    //连接le_search的returnPressed信号到槽函数，槽函数为搜索按钮，returnPressed是当用户在 QLineEdit 中按下回车键（Enter 键）时，这个信号会被发射
    connect(ui->le_search, &QLineEdit::returnPressed, this, &MainWindow::on_btn_search_clicked);

    //5.给标签添加事件过滤器
    //参数指定为this，也就是当前窗口对象MainWindow
    ui->lb_Top_Curve->installEventFilter(this);
    ui->lb_Bottom_Curve->installEventFilter(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

//重写父类的虚函数
//父类中默认的的实现 是忽略右键菜单事件
//重写之后，就可以处理右键菜单
void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{
    //弹出右键菜单
    mExitMenu->exec(QCursor::pos());

    event->accept();
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    mOffset = event->globalPos() - this->pos(); //this->pos()是窗口左上角位置
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    this->move(event->globalPos() - mOffset);
}

void MainWindow::getWeatherInfo(QString cityName)
{
    qDebug() << cityName;
    QString cityCode = CityCode::getCityCode(cityName);
    qDebug() << cityCode;
    if (cityCode.isEmpty()) {
        QMessageBox::warning(this, "天气", "请检查输入是否正确！", QMessageBox::Ok);
        return;
    }
    QUrl url("http://t.weather.itboy.net/api/weather/city/" + cityCode);
    mNetAccessManger->get(QNetworkRequest(url));
}

void MainWindow::parseJson(QByteArray &byteArray)
{
    QJsonParseError err;
    QJsonDocument doc = QJsonDocument::fromJson(byteArray, &err);
    if (err.error != QJsonParseError::NoError) {
        return;
    }
    QJsonObject rootObj = doc.object();
    //qDebug()<<rootObj.value("message").toString();

    //1.解析日期和城市
    mToday.date = rootObj.value("date").toString();
    mToday.city = rootObj.value("cityInfo").toObject().value("city").toString();

    //2.解析yesterday(昨天)
    QJsonObject objData = rootObj.value("data").toObject();

    QJsonObject objYesterday = objData.value("yesterday").toObject();

    mDay[0].week = objYesterday.value("week").toString();
    mDay[0].date = objYesterday.value("ymd").toString();
    mDay[0].type = objYesterday.value("type").toString();
    QString s;
    s = objYesterday.value("high").toString().split(" ").at(1); //18°
    s = s.left(s.length() - 1);                                 //18
    mDay[0].high = s.toInt();

    s = objYesterday.value("low").toString().split(" ").at(1); //18°
    s = s.left(s.length() - 1);                                //18
    mDay[0].high = s.toInt();

    //风向风力
    mDay[0].fx = objYesterday.value("fx").toString();
    mDay[0].fl = objYesterday.value("fl").toString();

    //污染指数
    mDay[0].aqi = objYesterday.value("aqi").toDouble();

    //3.解析forcast中5天的数据
    QJsonArray forecastArr = objData.value("forecast").toArray();

    for (int i = 0; i < 5; i++) {
        QJsonObject objForecast = forecastArr[i].toObject();
        mDay[i + 1].week = objForecast.value("week").toString();
        mDay[i + 1].date = objForecast.value("ymd").toString();

        //天气类型
        mDay[i + 1].type = objForecast.value("type").toString();

        //高温低温
        QString s;
        s = objForecast.value("high").toString().split(" ").at(1); //18°
        //qDebug()<<objForecast.value("high").toString().split(" ").at(1);
        s = s.left(s.length() - 1); //18
        //qDebug()<<s;
        mDay[i + 1].high = s.toInt();

        s = objForecast.value("low").toString().split(" ").at(1); //18°
        s = s.left(s.length() - 1);                               //18
        mDay[i + 1].low = s.toInt();

        //风向风力
        mDay[i + 1].fx = objForecast.value("fx").toString();
        mDay[i + 1].fl = objForecast.value("fl").toString();

        //污染指数
        mDay[i + 1].aqi = objForecast.value("aqi").toInt();

        //温馨提示
        mDay[i].notice = objForecast.value("notice").toString();
    }

    //4.解析今天的数据
    mToday.ganmao = objData.value("ganmao").toString();
    mToday.wendu = static_cast<int>(objData.value("wendu").toString().toDouble());
    mToday.shidu = objData.value("shidu").toString();
    mToday.pm25 = objData.value("pm25").toDouble();
    mToday.quality = objData.value("quality").toString();

    //5.fotcast中第一个数组元素,也是今天的数据
    mToday.type = mDay[1].type;
    mToday.fx = mDay[1].fx;
    mToday.fl = mDay[1].fl;
    mToday.high = mDay[1].high;
    mToday.low = mDay[1].low;

    //6.更新UI
    updateUI();

    //6.2绘制温度曲线
    ui->lb_Top_Curve->update();
    ui->lb_Bottom_Curve->update();
}

void MainWindow::updateUI()
{
    //1.更新日期和城市
    ui->label_Date->setText(QDateTime::fromString(mToday.date, "yyyyMMdd").toString("yyyy/MM/dd")
                            + " " + mDay[1].week);
    ui->lb_Area->setText(mToday.city);

    //2.更新今天
    // 获取 QLabel 的宽度和高度
    int labelWidth = ui->lbTypeIcon->width();
    int labelHeight = ui->lbTypeIcon->height();

    // 缩放图片以适应 QLabel 的大小
    QPixmap scaledPixmap = mTypeMap[mToday.type];

    // 设置缩放后的图片为 QLabel 的 pixmap,Qt::KeepAspectRatio保持图像的宽高比，缩放后的图像不会变形，Qt::SmoothTransformation使用平滑的缩放算法，缩放速度较慢，但图像质量较好，减少了锯齿和模糊
    ui->lbTypeIcon->setPixmap(
        scaledPixmap.scaled(labelWidth, labelHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation));

    //设置图片填充满lbTypeIcon控件
    //ui->lbTypeIcon->setScaledContents(true);

    //qDebug()<<mTypeMap[mToday.type];
    ui->label_Temperature->setText(QString::number(mToday.wendu) + "°");
    ui->label_Weather->setText(mToday.type);
    ui->label_Range->setText(QString::number(mToday.low) + "°" + "~" + QString::number(mToday.high)
                             + "°");

    //感冒指数也可改为温馨提示，注释其中一句即可
    ui->lb_GanMao->setText("感冒指数：" + mToday.ganmao);
    //温馨提示
    //ui->lb_GanMao->setText("温馨提示："+mDay[1].notice);

    ui->lb_WindFx->setText(mToday.fx);
    ui->lb_WindFI->setText(mToday.fl);
    ui->lb_PM25->setText(QString::number(mToday.pm25));
    ui->lb_Shidu->setText(mToday.shidu);
    ui->lb_Quality->setText(mToday.quality);

    //3.更新6天
    for (int i = 0; i < 6; i++) {
        //3.1更新日期和时间
        mWeekList[i]->setText("周" + mDay[i].week.right(1));
        ui->lb_Week1->setText("昨天");
        ui->lb_Week2->setText("今天");
        ui->lb_Week3->setText("明天");

        QStringList ymdList = mDay[i].date.split("-");
        mDateList[i]->setText(ymdList[1] + "/" + ymdList[2]);

        //3.2更新天气类型
        // 获取 QLabel 的宽度和高度
        int labelWidth = mTypeIconList[i]->width();
        int labelHeight = mTypeIconList[i]->height();
        //qDebug()<<mDay[i].type;
        QPixmap scaledPixmap = mTypeMap[mDay[i].type];
        mTypeIconList[i]->setPixmap(scaledPixmap.scaled(labelWidth,
                                                        labelHeight,
                                                        Qt::KeepAspectRatio,
                                                        Qt::SmoothTransformation));
        mTypeList[i]->setText(mDay[i].type);

        //3.3更新空气质量
        if (mDay[i].aqi >= 0 && mDay[i].aqi <= 50) {
            mAqiList[i]->setText("优");
            mAqiList[i]->setStyleSheet("background-color: rgb(121,184,0);");
        } else if (mDay[i].aqi > 50 && mDay[i].aqi <= 100) {
            mAqiList[i]->setText("良");
            mAqiList[i]->setStyleSheet("background-color: rgb(255,187,23);");
        } else if (mDay[i].aqi > 100 && mDay[i].aqi <= 150) {
            mAqiList[i]->setText("轻度");
            mAqiList[i]->setStyleSheet("background-color: rgb(255,87,97);");
        } else if (mDay[i].aqi > 150 && mDay[i].aqi <= 200) {
            mAqiList[i]->setText("中度");
            mAqiList[i]->setStyleSheet("background-color: rgb(235,17,27);");
        } else if (mDay[i].aqi > 200 && mDay[i].aqi <= 250) {
            mAqiList[i]->setText("重度");
            mAqiList[i]->setStyleSheet("background-color: rgb(170,0,0);");
        } else {
            mAqiList[i]->setText("严重");
            mAqiList[i]->setStyleSheet("background-color: rgb(110,0,0);");
        }

        //3.4更新风力风向
        mFxList[i]->setText(mDay[i].fx);
        mFlList[i]->setText(mDay[i].fl);
    }
}

bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == ui->lb_Top_Curve && event->type() == QEvent::Paint) {
        paintTopCurve();
    }
    if (watched == ui->lb_Bottom_Curve && event->type() == QEvent::Paint) {
        paintBottomCurve();
    }
    return QWidget::eventFilter(watched, event);
}

void MainWindow::paintTopCurve()
{
    QPainter painter(ui->lb_Top_Curve);
    //抗锯齿
    painter.setRenderHint(QPainter::Antialiasing, true);

    //1.x坐标
    int pointX[6] = {0};
    for (int i = 0; i < 6; i++) {
        pointX[i] = mWeekList[i]->pos().x() + mWeekList[i]->width() / 2;
    }

    int tempSum = 0;
    int tempAverage = 0;
    for (int i = 0; i < 6; i++) {
        tempSum += mDay[i].high;
    }
    tempAverage = tempSum / 6; //最高温的平均值
    //qDebug()<<tempAverage;

    //2.y的坐标

    int pointY[6] = {0};
    int yCenter = ui->lb_Top_Curve->height() / 2;
    for (int i = 0; i < 6; i++) {
        //qDebug()<<mDay[i].high;
        pointY[i] = yCenter - ((mDay[i].high - tempAverage) * INCREMENT);
        //qDebug()<<pointY[i];
    }

    //3.开始绘制
    //3.1初始化画笔相关
    QPen pen = painter.pen();
    pen.setWidth(1);                   //设置画笔的宽度
    pen.setColor(QColor(255, 170, 0)); //设置画笔的颜色

    painter.setPen(pen);
    painter.setBrush(QColor(255, 170, 0)); //设置画刷的颜色-内部填充的颜色

    //3.2画点，写文本
    for (int i = 0; i < 6; i++) {
        //显示点
        painter.drawEllipse(QPoint(pointX[i], pointY[i]), POINT_RADIUS, POINT_RADIUS);

        //显示文本
        painter.drawText(pointX[i] - TEXT_OFFSET_X,
                         pointY[i] - TEXT_OFFSET_Y,
                         QString::number(mDay[i].high) + "°");
    }

    //3.3绘制曲线
    for (int i = 0; i < 5; i++) {
        if (i == 0) {
            pen.setStyle(Qt::DotLine); //虚线
            painter.setPen(pen);
        } else {
            pen.setStyle(Qt::SolidLine); //实线
            painter.setPen(pen);
        }
        painter.drawLine(pointX[i], pointY[i], pointX[i + 1], pointY[i + 1]);
    }
}

void MainWindow::paintBottomCurve()
{
    QPainter painter(ui->lb_Bottom_Curve);
    //抗锯齿
    painter.setRenderHint(QPainter::Antialiasing, true);

    //1.x坐标
    int pointX[6] = {0};
    for (int i = 0; i < 6; i++) {
        pointX[i] = mWeekList[i]->pos().x() + mWeekList[i]->width() / 2;
    }
    int tempSum = 0, tempAverage = 0;
    for (int i = 0; i < 6; i++) {
        tempSum += mDay[i].low;
    }
    tempAverage = tempSum / 6; //最高温的平均值
    //2.y坐标
    int pointY[6] = {0};
    int yCenter = ui->lb_Bottom_Curve->height() / 2;
    for (int i = 0; i < 6; i++) {
        pointY[i] = yCenter - ((mDay[i].low - tempAverage) * INCREMENT);
    }

    //3.开始绘制
    //3.1初始化画笔相关
    QPen pen = painter.pen();
    pen.setWidth(1);                   //设置画笔的宽度
    pen.setColor(QColor(0, 255, 255)); //设置画笔的颜色
    painter.setPen(pen);
    painter.setBrush(QColor(0, 255, 255)); //设置画刷的颜色-内部填充的颜色

    //3.2画点，写文本
    for (int i = 0; i < 6; i++) {
        //显示点
        painter.drawEllipse(QPoint(pointX[i], pointY[i]), POINT_RADIUS, POINT_RADIUS);

        //显示文本
        painter.drawText(pointX[i] - TEXT_OFFSET_X,
                         pointY[i] - TEXT_OFFSET_Y,
                         QString::number(mDay[i].low) + "°");
    }

    //3.3绘制曲线
    for (int i = 0; i < 5; i++) {
        if (i == 0) {
            pen.setStyle(Qt::DotLine); //虚线
            painter.setPen(pen);
        } else {
            pen.setStyle(Qt::SolidLine); //实线
            painter.setPen(pen);
        }
        painter.drawLine(pointX[i], pointY[i], pointX[i + 1], pointY[i + 1]);
    }
}

void MainWindow::locationInfo()
{
    QUrl url("http://whois.pconline.com.cn/ipJson.jsp?json=true");
    mLocationManger->get(QNetworkRequest(url));
}

void MainWindow::onLocationInfoReceived(QNetworkReply *reply)
{
    if (reply->error() == QNetworkReply::NoError) {
        QString data = QString::fromLocal8Bit(reply->readAll());
        QJsonDocument jsonDocument = QJsonDocument::fromJson(data.toUtf8());
        QJsonObject jsonObject = jsonDocument.object();
        qDebug() << "read all:" << jsonObject;
        mlocation.ip = jsonObject.value("ip").toString();
        mlocation.pro = jsonObject.value("pro").toString();
        mlocation.proCode = jsonObject.value("proCode").toString();
        mlocation.city = jsonObject.value("city").toString();
        mlocation.cityCode = jsonObject.value("cityCode").toString();

    } else {
        qDebug() << "Location request error: " << reply->errorString();
    }
    qDebug() << mlocation.city;
    //请求天气信息
    getWeatherInfo(mlocation.city);
    reply->deleteLater(); //deleteLater 是 Qt 框架中的一个方法，用于在对象的生命周期结束时安全地删除对象
}

bool MainWindow::is_virtual_network_card_or_loopback(QString str_card_name)
{
    if (-1 != str_card_name.indexOf("VMware") || -1 != str_card_name.indexOf("Loopback")
        || -1 != str_card_name.indexOf("VirtualBox"))
        return true;

    return false;
}

QString MainWindow::getIP()
{
    QList<QHostAddress> list = QNetworkInterface::allAddresses();
    foreach (QHostAddress address, list) {
        if (address.protocol() == QAbstractSocket::IPv4Protocol)
            return address.toString();
    }
    return "0.0.0.0";
}

void MainWindow::GetLocalIP(QMap<QString, int> &map_ip)
{
    // 1. 获取所有网络接口
    QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();

    QList<QNetworkAddressEntry> entry;
    foreach (QNetworkInterface inter, interfaces) {
        // 过滤掉vmware虚拟网卡和回环网卡
        if (is_virtual_network_card_or_loopback(inter.humanReadableName()))
            continue;

        if (inter.flags() & (QNetworkInterface::IsUp | QNetworkInterface::IsRunning)) {
            entry = inter.addressEntries();
            int cnt = entry.size() - 1;
            for (int i = 1; i <= cnt; ++i) {
                if (entry.at(i).ip().protocol() == QAbstractSocket::IPv4Protocol) {
                    if (-1 != inter.name().indexOf("wireless")) {
                        map_ip.insert(entry.at(i).ip().toString(), 0);
                    } else if (-1 != inter.name().indexOf("ethernet")) {
                        map_ip.insert(entry.at(i).ip().toString(), 1);
                    }
                }
            }
            entry.clear();
        }
    }
}

void MainWindow::onReplied(QNetworkReply *reply)
{
    //qDebug()<<"success";

    int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

    // qDebug()<<"operation："<<reply->operation();
    // qDebug()<<"Status code:"<<status_code;
    // qDebug()<<"url:"<<reply->url();
    // qDebug()<<"raw header:"<<reply->rawHeaderList();

    if (reply->error() != QNetworkReply::NoError || status_code != 200) {
        //qDebug()<<reply->error();
        QMessageBox::warning(this, "天气", "请求数据失败", QMessageBox::Ok);
    } else {
        //获取响应信息
        QByteArray byteArray = reply->readAll();
        //qDebug()<<"read all:"<<byteArray.data();
        parseJson(byteArray);
    }
    reply->deleteLater(); //deleteLater 是 Qt 框架中的一个方法，用于在对象的生命周期结束时安全地删除对象
}

void MainWindow::on_btn_search_clicked()
{
    QString cityName = ui->le_search->text();
    bool ok = (!cityName.isEmpty());
    if (ok) {
        getWeatherInfo(cityName);
    } else {
        QMessageBox::information(NULL, NULL, "输入为空");
    }
}
